home *** CD-ROM | disk | FTP | other *** search
/ Steal This CD / steal_this_cd.iso / Chapter 07 - Where the Hackers Are / virc200.exe / {app} / Scripts / schat.vsc < prev    next >
Text File  |  2003-05-16  |  42KB  |  1,262 lines

  1. // SimpleChat client/server for ViRC 2.0pre8 and above
  2. // Copyright 2001 Jesse McGrew (Mr2001) - u7hycyct02@sneakemail.com
  3.  
  4. // Message Of The Day (MOTD) - this will be sent to clients who connect to
  5. // any SimpleChat sessions that you are hosting.
  6. @ $SChatMOTD = SimpleChat hosted by ViRC $ver
  7.  
  8. // Default password mode:
  9. //  0 - no password required
  10. //  1 - master password (same for each connection)
  11. //  2 - individual passwords
  12. // you can change the password mode of an individual server with /pmode.
  13. @ $SChatPasswordMode = 2
  14.  
  15. // Debug mode - if enabled (1), you will see green network debug messages.
  16. @ $SChatDebugMode = 0
  17.  
  18. //-------------------------------------------------------------------------
  19.  
  20. // Version check
  21. if ($build < 200) || ($build == 200 && $prebuild > 0 && $prebuild < 11)
  22.   MessageBox This script requires ViRC 2.0pre11. Please download it from http://www.hansprestige.com/virc/beta.php
  23.   Halt
  24. endif
  25.  
  26. //-------------------------------------------------------------------------
  27.  
  28. // General SimpleChat window class
  29. Class TSimpleChatForm
  30.   // public
  31.   Property Nick
  32.   Property Caption read GetRelay write SetRelay
  33.   Property TabCaption read GetRelay write SetRelay
  34.   Property Visible read GetRelay write SetRelay
  35.   Property Whiteboard
  36.   //
  37.   Method TextOut
  38.     TextOut > %$prop($Self.Output) $1-
  39.   EndMethod
  40.   //
  41.   Method Clear
  42.     Clear %$prop($Self.Output)
  43.   EndMethod
  44.   //
  45.   Method Debug
  46.     if ($SChatDebugMode)
  47.       $Self.TextOut clGreen $1-
  48.     endif
  49.   EndMethod
  50.   //
  51.   // private/protected
  52.   Private Property Form
  53.   Private Property Input
  54.   Protected Property List
  55.   Private Property Output
  56.   Protected Property Socket
  57.   //
  58.   Private Method <Create>
  59.     @ $SChatForms = $listcat($SChatForms $Self)
  60.     
  61.     @l $form = $new(TTabbedForm $1-)
  62.     @p $Self.Form = $form
  63.     if ($fileexists(schat.ico))
  64.       $form.Icon.LoadFromFile schat.ico
  65.     endif
  66.     @p $form.Tag = $Self
  67.     @p $form.FormStyle = fsMDIChild
  68.     @p $form.Width = 541
  69.     @p $form.Height = 339
  70.     @p $form.OnClose = $Self.FormClosed
  71.     
  72.     @l $socket = $new(TSockets)
  73.     @p $Self.Socket = $socket
  74.     @p $socket.OnStateChanged = $Self.SocketStateChanged
  75.     
  76.     @l $input = $new(TInputMemo ownedby $form)
  77.     @p $Self.Input = $input
  78.     @p $input.Height = 24
  79.     @p $input.Align = alBottom
  80.     @p $input.OnKeyDown = $Self.InputKeyDown
  81.     @p $input.Font.Name = $getsetting(Fonts MainName)
  82.     @p $input.Font.Size = $getsetting(Fonts MainSize)
  83.     
  84.     @l $list = $new(TListBox ownedby $form)
  85.     @p $Self.List = $list
  86.     @p $list.Width = 105
  87.     @p $list.Align = alRight
  88.     @p $list.Sorted = True
  89.     @p $list.Font.Name = $getsetting(Fonts NickListName)
  90.     @p $list.Font.Size = $getsetting(Fonts NickListSize)
  91.     @p $list.OnDblClick = $Self.ListDblClick
  92.     
  93.     @l $output = $new(TMonkeySex ownedby $form)
  94.     @p $Self.Output = $output
  95.     @p $output.Align = alClient
  96.     @p $output.Font.Name = $getsetting(Fonts MainName)
  97.     @p $output.Font.Size = $getsetting(Fonts MainSize)
  98.     @p $output.OnCopyText = $Self.OutputCopyText
  99.     @p $output.OnHyperlink = $Self.OutputHyperlink
  100.   EndMethod
  101.   Private Method <Destroy>
  102.     SafeDestroy $prop($Self.Socket)
  103.     SafeDestroy $prop($Self.Form)
  104.     @ $SChatForms = $listremove($Self $SChatForms)
  105.   EndMethod
  106.   Private Method SetRelay
  107.     @p $prop($Self.Form).$1 = $2-
  108.   EndMethod
  109.   Private Method GetRelay
  110.     @ $fresult = $prop($prop($Self.Form).$1)
  111.   EndMethod
  112.   Method SocketStateChanged
  113.     $Self.Debug <state changed: $State>
  114.   EndMethod
  115.   Method InputKeyDown
  116.     @l $input = $prop($Self.Input)
  117.     switch $Key
  118.       case 27:
  119.         // escape
  120.         $input.Lines.Clear
  121.         @l $Key = 0
  122.       case 13:
  123.         // process commands from the input box
  124.         // the Cmd* methods are defined in the child classes
  125.         @l $count = $prop($input.Lines.Count)
  126.         for (@l $i = 0; $i < $count; $i++)
  127.           @l $line = $input.Lines.GetString($i)
  128.           continue if [$line] == []
  129.           
  130.           if ([$substr($line 1 1)] == [/])
  131.             Parse $line
  132.               switch $0
  133.                 case /say:
  134.                   $Self.CmdSay $1-
  135.                 case /me:
  136.                   $Self.CmdMe $1-
  137.                 case /kick:
  138.                   $Self.CmdKick $1-
  139.                 case /ban:
  140.                   $Self.CmdBan $1-
  141.                 case /nick:
  142.                   $Self.CmdNick $1-
  143.                 case /quit:
  144.                   $Self.CmdQuit $1-
  145.                 case /list:
  146.                   $Self.CmdList
  147.                 case multi /raw,/quote
  148.                   $Self.CmdQuote $1-
  149.                 case /wb:
  150.                   $Self.CmdWB
  151.                 case /bans:
  152.                   $Self.CmdBans
  153.                 case /unban:
  154.                   $Self.CmdUnban $1-
  155.                 case /invite:
  156.                   $Self.CmdInvite $1-
  157.                 case /pmode:
  158.                   $Self.CmdPMode $1-
  159.                 case multi /help,/?
  160.                   $Self.TextOut ecError *** SimpleChat commands: /say, /me, /kick, /ban, /nick, /quit, /list, /quote, /wb, /bans, /unban, /invite, /pmode
  161.                 case else
  162.                   // run as a regular ViRC command
  163.                   $line
  164.               endswitch
  165.             EndParse
  166.           else
  167.             $Self.CmdSay $line
  168.           endif
  169.         endfor
  170.         $input.Lines.Clear
  171.         @l $Key = 0
  172.     endswitch
  173.   EndMethod
  174.   Method OutputCopyText
  175.     SetClipboard $stripattrs($Text)
  176.   EndMethod
  177.   Method OutputHyperlink
  178.     WebHyperlink $Text
  179.   EndMethod
  180.   Method FormClosed
  181.     // close all connections
  182.     @l $socket = $prop($Self.Socket)
  183.     foreach ($i; $prop($Self.Users))
  184.       if ($listindex(0 $i) != 0)
  185.         $socket.SetActiveConnection $listindex(0 $i)
  186.         $socket.SClose
  187.       endif
  188.     endforeach
  189.     // destroy form
  190.     SafeDestroy $Self
  191.   EndMethod
  192.   Method ListDblClick
  193.     @l $list = $prop($Self.List)
  194.     @l $idx = $prop($list.ItemIndex)
  195.     if ($idx != -1)
  196.       $Self.TextOut ecScript *** $list.Items.GetString($idx)
  197.     endif
  198.   EndMethod
  199.   //
  200.   Protected Method HandleInfo
  201.     // HandleInfo INFO |cmd nick text
  202.     @l $cmd = $substr($2 2 9999)
  203.     switch $cmd
  204.       case WBOARD:
  205.         @l $wb = $prop($Self.Whiteboard)
  206.         if ([$wb] == [])
  207.           // create whiteboard
  208.           @l $form = $prop($Self.Form)
  209.           @l $wb = $newwhiteboard(SimpleChat: $prop($form.TabCaption))
  210.           @p $Self.Whiteboard = $wb
  211.         endif
  212.         Whiteboard $wb simulate $4-
  213.       case MOTD:
  214.         $Self.TextOut ecNotice *** \b$4-\b
  215.     endswitch
  216.   EndMethod
  217.   //
  218.   Method CmdWB
  219.     @l $wb = $prop($Self.Whiteboard)
  220.     if ([$wb] == [])
  221.       // create whiteboard
  222.       @l $form = $prop($Self.Form)
  223.       @l $wb = $newwhiteboard(SimpleChat: $prop($form.TabCaption))
  224.       @p $Self.Whiteboard = $wb
  225.     endif
  226.     // show whiteboard form
  227.     @l $obj = $mapobject($wb)
  228.     $obj.BringToFront
  229.     $obj.SetFocus
  230.     UnmapObject $obj
  231.   EndMethod
  232. EndClass
  233.  
  234. // client form
  235. Class TSimpleChatClient extends TSimpleChatForm
  236.   // public
  237.   Property Connected nowrite
  238.   Property Registered nowrite
  239.   Method PutServ
  240.     @l $socket = $prop($Self.Socket)
  241.     $socket.SendCRLF $1-
  242.   EndMethod
  243.   Method Connect
  244.     @l $socket = $prop($Self.Socket)
  245.     @p $socket.IPAddr = $1
  246.     @p $socket.Port = $2
  247.     @p $Self.Password = $3
  248.     $Self.TextOut ecNotice *** Connecting to $1:$2...
  249.     $socket.SConnect
  250.   EndMethod
  251.   //
  252.   // private
  253.   Private Property Password
  254.   Private Property Buffer
  255.   Private Property GettingList
  256.   Private Property TryingNick
  257.   //
  258.   Private Method <Create>
  259.     Inherited <Create> $1-
  260.     @l $socket = $prop($Self.Socket)
  261.     @p $socket.OnErrorOccurred = $Self.SocketErrorOccurred
  262.     @p $socket.OnSessionConnected = $Self.SocketSessionConnected
  263.     @p $socket.OnSessionClosed = $Self.SocketSessionClosed
  264.     @p $socket.OnDataAvailable = $Self.SocketDataAvailable
  265.     
  266.     @p $Self.Connected = 0
  267.     @p $Self.Registered = 0
  268.     @p $Self.GettingList = 0
  269.     @p $Self.TryingNick = 0
  270.   EndMethod
  271.   Private Method <Destroy>
  272.     if ($prop($Self.Connected))
  273.       @l $socket = $prop($Self.Socket)
  274.       $socket.SClose
  275.     endif
  276.     Inherited <Destroy> $1-
  277.   EndMethod
  278.   Method SocketErrorOccurred
  279.     $Self.TextOut ecError *** Socket error $Error ($Msg)
  280.     switch $Error
  281.       case multi 0,10053,10054,10060,11001
  282.         $Sender.SClose
  283.         @p $Self.Connected = 0
  284.     endswitch
  285.   EndMethod
  286.   Method SocketSessionConnected
  287.     $Self.Debug <session connected>
  288.     @p $Self.Connected = 1
  289.     @l $pass = $prop($Self.Password)
  290.     if ([$pass] == [])
  291.       $Self.PutServ NICK |$prop($Self.Nick)
  292.     else
  293.       $Self.PutServ NICK |$prop($Self.Nick) $pass
  294.     endif
  295.   EndMethod
  296.   Method SocketSessionClosed
  297.     $Self.TextOut ecNotice *** Connection closed by remote host
  298.     // update tab caption
  299.     @l $form = $prop($Self.Form)
  300.     @p $form.TabCaption = disconnected
  301.   EndMethod
  302.   Method SocketDataAvailable
  303.     $Self.Debug <data available>
  304.     @l $buffer = $prop($Self.Buffer)$prop($Sender.Text)
  305.     @l $idx = $strpos($char(10) $buffer)
  306.     while ($idx != 0)
  307.       // extract a line
  308.       @l $line = $substr($buffer 1 $($idx - 1))
  309.       if ([$substr($line $length($line) 1)] == [$char(13)])
  310.         @l $line = $substr($line 1 $($length($line) - 1))
  311.       endif
  312.       $Self.Debug <line: $line>
  313.       @l $buffer = $substr($buffer $($idx + 1) $length($buffer))
  314.       
  315.       switch $line
  316.         case LIST |START:
  317.           @l $list = $prop($Self.List)
  318.           $list.Items.Clear
  319.           $list.Items.Add $prop($Self.Nick) (me)
  320.           @p $Self.GettingList = 1
  321.         case LIST |END:
  322.           @p $Self.GettingList = 0
  323.         case matches JOIN |*
  324.           Parse $strtokr(| $line)
  325.             $Self.TextOut ecJoin *** \b$0\b ($1) has joined the chat
  326.             @l $list = $prop($Self.List)
  327.             $list.Items.Add $0 ($1)
  328.           EndParse
  329.         case matches KICK |*
  330.           Parse $strtokr(| $line)
  331.             $Self.TextOut ecKick *** \b$0\b was kicked [$1-]
  332.             @l $list = $prop($Self.List)
  333.             $list.Items.Delete $list.Items.IndexOfMask($0 *)
  334.           EndParse
  335.         case matches QUIT |*
  336.           Parse $strtokr(| $line)
  337.             $Self.TextOut ecQuit *** \b$0\b has quit the chat [$1-]
  338.             @l $list = $prop($Self.List)
  339.             $list.Items.Delete $list.Items.IndexOfMask($0 *)
  340.           EndParse
  341.         case matches BAN |*
  342.           $Self.TextOut ecNotice *** \bYou have been banned\b: $strtokr(| $line)
  343.         case matches NICK |*
  344.           Parse $strtokr(| $line)
  345.             // server sends 'NICK |mynick' when we connect
  346.             @p $Self.Registered = 1
  347.             if ([$1] != [])
  348.               // nick change
  349.               if ([$0] == [$prop($Self.Nick)])
  350.                 @p $Self.Nick = $1
  351.               endif
  352.               $Self.TextOut ecNick *** \b$0\b is now known as \b$1\b
  353.               @l $list = $prop($Self.List)
  354.               @l $idx = $list.Items.IndexOfMask($0 *)
  355.               if ($idx >= 0)
  356.                 @l $newnick = $1
  357.                 Parse $list.Items.GetString($idx)
  358.                   $list.Items.SetString $idx $newnick $1-
  359.                 EndParse
  360.               endif
  361.             endif
  362.           EndParse
  363.         case matches ERR |*
  364.           $Self.TextOut ecError *** Error: $strtokr(| $line)
  365.           
  366.           // nick in use while registering? try default nicks from client setup
  367.           Parse $line
  368.             if ([$1] == [|NICK]) && ($prop($Self.Registered) == 0)
  369.               @l $num = $prop($Self.TryingNick)
  370.               $num++
  371.               if ($num > $getsetting(NickCount))
  372.                 // no more nicks to try
  373.                 @l $nick = $?="Your nickname is in use. Enter another nickname to try:"
  374.                 if ([$nick] == [INPUT_CANCELLED])
  375.                   @l $nick = $null
  376.                 endif
  377.               else
  378.                 @l $nick = $getsetting(Nick$num)
  379.                 while ([$nick] == [$prop($Self.Nick)])
  380.                   $num++
  381.                   @l $nick = $getsetting(Nick$num)
  382.                 endwhile
  383.                 @p $Self.TryingNick = $num
  384.               endif
  385.               if ([$nick] != [])
  386.                 @p $Self.Nick = $nick
  387.                 $Self.TextOut ecNotice *** Trying $nick...
  388.                 $Self.PutServ NICK |$nick $prop($Self.Password)
  389.               endif
  390.             endif
  391.           EndParse
  392.         case matches INFO |*
  393.           $Self.HandleInfo $line
  394.         case matches % |*
  395.           //$Self.TextOut ecError *** Unknown server info event received: $strtokl(| $line)
  396.         case matches % :*
  397.           Parse $line
  398.             $Self.TextOut ecChanText <\b$0\b>\t$strtrim($1-)
  399.           EndParse
  400.         case matches % >*
  401.           Parse $line
  402.             $Self.TextOut ecAction  * \b$0\b $strtokr(> $1-)
  403.           EndParse
  404.         case else
  405.           if ($prop($Self.GettingList))
  406.             @l $list = $prop($Self.List)
  407.             Parse $line
  408.               $list.Items.Add $0 ($1)
  409.             EndParse
  410.           else
  411.             $Self.TextOut ecError *** Unknown server line received: $line
  412.           endif
  413.       endswitch
  414.       
  415.       // find next line
  416.       @l $idx = $strpos($char(10) $buffer)
  417.     endwhile
  418.     
  419.     @p $Self.Buffer = $buffer
  420.   EndMethod
  421.   // command handlers
  422.   Method CmdSay
  423.     $Self.TextOut ecMyChanText [\b$prop($Self.Nick)\b]\t$1-
  424.     $Self.PutServ :$1-
  425.   EndMethod
  426.   Method CmdMe
  427.     $Self.TextOut ecAction  * \b$prop($Self.Nick)\b $1-
  428.     $Self.PutServ >$1-
  429.   EndMethod
  430.   Method CmdKick
  431.     $Self.TextOut ecError *** You are not the server
  432.   EndMethod
  433.   Method CmdBan
  434.     $Self.TextOut ecError *** You are not the server
  435.   EndMethod
  436.   Method CmdUnban
  437.     $Self.TextOut ecError *** You are not the server
  438.   EndMethod
  439.   Method CmdBans
  440.     $Self.TextOut ecError *** You are not the server
  441.   EndMethod
  442.   Method CmdInvite
  443.     $Self.TextOut ecError *** You are not the server
  444.   EndMethod
  445.   Method CmdPMode
  446.     $Self.TextOut ecError *** You are not the server
  447.   EndMethod
  448.   Method CmdNick
  449.     $Self.PutServ NICK |$1-
  450.   EndMethod
  451.   Method CmdQuit
  452.     $Self.PutServ QUIT |$1-
  453.   EndMethod
  454.   Method CmdQuote
  455.     $Self.PutServ $1-
  456.   EndMethod
  457.   Method CmdList
  458.     $Self.PutServ LIST |
  459.   EndMethod
  460.   //
  461.   Method SendWB
  462.     $Self.PutServ INFO |WBOARD $1-
  463.   EndMethod
  464. EndClass
  465.  
  466. // server form
  467. Class TSimpleChatServer extends TSimpleChatForm
  468.   // public
  469.   Property Address nowrite
  470.   Property Port nowrite
  471.   // 0=no passwords, 1=serverwide password (group invitation), 2=individual passwords (personal invitation)
  472.   Property PasswordMode
  473.   //
  474.   Method PutClient
  475.     @l $socket = $prop($Self.Socket)
  476.     $socket.SetActiveConnection $1
  477.     $socket.SendCRLF $2-
  478.   EndMethod
  479.   Method PutAll
  480.     @l $socket = $prop($Self.Socket)
  481.     foreach ($i; $prop($Self.Users))
  482.       if ($listindex(2 $i) == 1)
  483.         $socket.SetActiveConnection $listindex(0 $i)
  484.         $socket.SendCRLF $1-
  485.       endif
  486.     endforeach
  487.   EndMethod
  488.   Method PutAllBut
  489.     // PutAllBut <socknum> <text>
  490.     @l $socket = $prop($Self.Socket)
  491.     foreach ($i; $prop($Self.Users))
  492.       if ($listindex(0 $i) != $1) && ($listindex(2 $i) == 1)
  493.         $socket.SetActiveConnection $listindex(0 $i)
  494.         $socket.SendCRLF $2-
  495.       endif
  496.     endforeach
  497.   EndMethod
  498.   Method Listen
  499.     // grab local ip address from server socket
  500.     @l $servsock = $mapobject(.:Sock)
  501.     @p $Self.Address = $prop($servsock.LocalIPAddr)
  502.     UnmapObject $servsock
  503.     // initialize users
  504.     @p $Self.Users = <0 $prop($Self.Nick) 2 $prop($Self.Address) none>
  505.     // initialize list box
  506.     @l $list = $prop($Self.List)
  507.     $list.Items.Add $prop($Self.Nick) (me)
  508.     // listen for connections
  509.     @l $socket = $prop($Self.Socket)
  510.     @p $Self.Port = $socket.SListenOnFreePort()
  511.     $Self.TextOut ecNotice *** Listening on $prop($Self.Address):$prop($Self.Port)...
  512.   EndMethod
  513.   //
  514.   Method GenPassword
  515.     @l $passchars = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@!.
  516.     @ $fresult = $null
  517.     // pick 8 random chars
  518.     for (@l $i = 1; $i <= 8; $i++)
  519.       @l $char = $substr($passchars $($rand($length($passchars)) + 1) 1)
  520.       @ $fresult = $fresult$char
  521.     endfor
  522.     @p $Self.Passwords = $listcat($prop($Self.Passwords) $fresult)
  523.   EndMethod
  524.   Method ClientExists
  525.     // $Self.ClientExists(Mr2001)
  526.     foreach ($i; $prop($Self.Users))
  527.       if ($listindex(2 $i) != 0) && ([$listindex(1 $i)] == [$1])
  528.         @ $fresult = 1
  529.         Halt
  530.       endif
  531.     endforeach
  532.     @ $fresult = 0
  533.   EndMethod
  534.   Method ValidNick
  535.     @l $letter = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
  536.     @l $digit = 0123456789
  537.     @l $special = []\`_^{|}
  538.     
  539.     @ $fresult = 0
  540.     
  541.     // first character must be letter or special
  542.     Halt if $strpos($substr($1- 1 1) $letter$special) == 0
  543.     
  544.     // rest must be letter, digit, or special
  545.     for (@l $i = 2; $i <= $length($1-); $i++)
  546.       Halt if $strpos($substr($1- $i 1) $letter$digit$special) == 0
  547.     endfor
  548.     
  549.     @ $fresult = 1
  550.   EndMethod
  551.   //
  552.   // private
  553.   // users entries: <socket> <nick> <state> <ip> <password>
  554.   // <state>... 0=waiting, 1=connected, 2=local
  555.   Protected Property Users
  556.   Protected Property Bans
  557.   Private Property Passwords
  558.   Private Property Buffers
  559.   //
  560.   Private Method <Create>
  561.     Inherited <Create> $1-
  562.     @l $socket = $prop($Self.Socket)
  563.     @p $socket.OnErrorOccurred = $Self.SocketErrorOccurred
  564.     @p $socket.OnSessionAvailable = $Self.SocketSessionAvailable
  565.     @p $socket.OnSessionClosed = $Self.SocketSessionClosed
  566.     @p $socket.OnDataAvailable = $Self.SocketDataAvailable
  567.     @p $Self.Users = $null
  568.     @p $Self.Bans = $null
  569.     @p $Self.ServerPassword = $null
  570.     @p $Self.Buffers = $null
  571.     @p $Self.PasswordMode = $SChatPasswordMode
  572.     @p $Self.Port = 0
  573.   EndMethod
  574.   Private Method <Destroy>
  575.     if ($prop($Self.Port) != 0)
  576.       @l $socket = $prop($Self.Socket)
  577.       $socket.SCancelListen
  578.     endif
  579.     Inherited <Destroy> $1-
  580.   EndMethod
  581.   Method SocketErrorOccurred
  582.     $Self.TextOut ecError *** Socket error $Error ($Msg)
  583.     switch $Error
  584.       case multi 0,10053,10054,10060,11001
  585.         $Sender.SClose
  586.     endswitch
  587.   EndMethod
  588.   Method SocketSessionAvailable
  589.     $Self.Debug <session available>
  590.     @l $num = $Sender.SAccept()
  591.     @l $idx = $listelementcount($prop($Self.Users))
  592.     @p $Self.Users = $listcat($prop($Self.Users) <$num ??? 0 $prop($Sender.RemoteIPAddr) ???>)
  593.     @p $Self.Buffers = $listreplace($idx $idx "" $prop($Self.Buffers))
  594.   EndMethod
  595.   Method SocketSessionClosed
  596.     $Self.Debug <session closed>
  597.     // find dead client's nick, build new list
  598.     @l $nick = <BUG>
  599.     @l $newlist = $null
  600.     foreach ($i; $prop($Self.Users))
  601.       if ($listindex(0 $i) == $Socket)
  602.         @l $nick = $listindex(1 $i)
  603.       else
  604.         @l $newlist = $listcat($newlist $listquote($i))
  605.       endif
  606.     endforeach
  607.     @p $Self.Users = $newlist
  608.     // announce quit
  609.     foreach ($i; $newlist)
  610.       if ($listindex(2 $i) == 1)
  611.         $Self.PutClient $listindex(0 $i) QUIT |$nick Socket closed
  612.       endif
  613.     endforeach
  614.     // announce locally
  615.     $Self.TextOut ecQuit *** \b$nick\b has left the chat [Socket closed]
  616.     // and update the listbox
  617.     @l $list = $prop($Self.List)
  618.     @l $idx = $list.Items.IndexOfMask($nick *)
  619.     if ($idx != -1)
  620.       $list.Items.Delete $idx
  621.     endif
  622.   EndMethod
  623.   Method SocketDataAvailable
  624.     $Self.Debug <data available>
  625.     $Sender.SetActiveConnection $Socket
  626.     @l $cnum = 0
  627.     @l $buffer = $null
  628.     @l $client = <BUG>
  629.     @l $state = -1
  630.     @l $ip = 0.0.0.0
  631.     @l $users = $prop($Self.Users)
  632.     foreach ($i; $users)
  633.       if ($listindex(0 $i) == $Socket)
  634.         @l $client = $listindex(1 $i)
  635.         @l $state = $listindex(2 $i)
  636.         @l $ip = $listindex(3 $i)
  637.         @l $buffer = $listindex($cnum $prop($Self.Buffers))
  638.         Break
  639.       endif
  640.       $cnum++
  641.     endforeach
  642.     
  643.     @l $buffer = $buffer$prop($Sender.Text)
  644.     @l $idx = $strpos($char(10) $buffer)
  645.     while ($idx != 0)
  646.       // extract a line
  647.       @l $line = $substr($buffer 1 $($idx - 1))
  648.       if ([$substr($line $length($line) 1)] == [$char(13)])
  649.         @l $line = $substr($line 1 $($length($line) - 1))
  650.       endif
  651.       $Self.Debug <line: $line>
  652.       @l $buffer = $substr($buffer $($idx + 1) $length($buffer))
  653.       
  654.       if ($state == 0)
  655.         // unregistered clients can only send NICK
  656.         Parse $line
  657.           if ([$0] == [NICK])
  658.             // check bans and validate password
  659.             if ($listindexof($ip $prop($Self.Bans)) != -1)
  660.               // banned
  661.               @l $valid = 0
  662.             else if ($strpos(* $2)) || ($strpos(? $2)) || ($strpos(% $2))
  663.               // no wildcard passwords, please
  664.               @l $valid = 0
  665.             else
  666.               switch $prop($Self.PasswordMode)
  667.                 case 0:
  668.                   // no passwords
  669.                   @l $valid = 1
  670.                 case 1:
  671.                   // master password
  672.                   @l $valid = $($listindexof($2 $prop($Self.Passwords)) >= 0)
  673.                 case 2:
  674.                   // individual passwords
  675.                   // each password is removed from the list after it is validated
  676.                   @l $passwords = $prop($Self.Passwords)
  677.                   if ($listindexof($2 $passwords) >= 0)
  678.                     @l $valid = 1
  679.                     @p $Self.Passwords = $listremove($2 $passwords)
  680.                   else
  681.                     @l $valid = 0
  682.                   endif
  683.               endswitch
  684.             endif
  685.             
  686.             if !($valid)
  687.               $Sender.SendCRLF ERR |NICK Access denied.
  688.               $Sender.SClose
  689.               // announce locally
  690.               $Self.TextOut ecError *** Unauthorized connection attempt from $substr($1 2 15) ($ip)
  691.             else
  692.               // valid password
  693.               @l $nick = $substr($1 2 15)
  694.               @l $pass = $3
  695.               // make sure nick is valid and not in use
  696.               if !($Self.ValidNick($nick))
  697.                 $Sender.SendCRLF ERR |NICK Invalid nickname.
  698.                 // add password back
  699.                 if ($listindexof($2 $prop($Self.Passwords)) == -1)
  700.                   @p $Self.Passwords = $listcat($prop($Self.Passwords) $2)
  701.                 endif
  702.               else if ($Self.ClientExists($nick))
  703.                 $Sender.SendCRLF ERR |NICK Nickname in use.
  704.                 // add password back
  705.                 if ($listindexof($2 $prop($Self.Passwords)) == -1)
  706.                   @p $Self.Passwords = $listcat($prop($Self.Passwords) $2)
  707.                 endif
  708.               else
  709.                 // acknowledge
  710.                 $Sender.SendCRLF NICK |$nick
  711.                 // send list
  712.                 $Sender.SendCRLF LIST |START
  713.                 foreach ($i; $prop($Self.Users))
  714.                   if ($listindex(0 $i) != $Socket) && ($listindex(2 $i) != 0)
  715.                     $Sender.SendCRLF $listindex(1 $i) $listindex(3 $i)
  716.                   endif
  717.                 endforeach
  718.                 $Sender.SendCRLF LIST |END
  719.                 
  720.                 // update users list
  721.                 @l $newlist = $null
  722.                 foreach ($i; $prop($Self.Users))
  723.                   if ($listindex(0 $i) == $Socket)
  724.                     // replace nick field with chosen nickname
  725.                     @l $newitem = $listreplace(1 1 $nick $i)
  726.                     // replace state with 1
  727.                     @l $newitem = $listreplace(2 2 1 $newitem)
  728.                     // save password
  729.                     @l $newitem = $listreplace(4 4 $2 $newitem)
  730.                   else
  731.                     // just append the entry
  732.                     @l $newitem = $i
  733.                     // announce the join
  734.                     if ($listindex(2 $i) == 1)
  735.                       $Self.PutClient $listindex(0 $i) JOIN |$nick $ip
  736.                     endif
  737.                   endif
  738.                   @l $newlist = $listcat($newlist $listquote($newitem))
  739.                 endforeach
  740.                 @p $Self.Users = $newlist
  741.                 
  742.                 // send motd
  743.                 $Self.PutClient $Socket INFO |MOTD $prop($Self.Nick) $SChatMOTD
  744.                 
  745.                 // display join locally
  746.                 $Self.TextOut ecJOIN *** \b$nick\b ($ip) has joined the chat
  747.                 // and add to listbox
  748.                 @l $list = $prop($Self.List)
  749.                 $list.Items.Add $nick ($ip)
  750.               endif
  751.             endif
  752.           endif
  753.         EndParse
  754.       else
  755.         // connected client
  756.         switch $line
  757.           case LIST |:
  758.             $Sender.SendCRLF LIST |START
  759.             foreach ($i; $prop($Self.Users))
  760.               // send this entry if it isn't the client and the state isn't 0
  761.               if ($listindex(0 $i) != $Socket) && ($listindex(2 $i) != 0)
  762.                 $Sender.SendCRLF $listindex(1 $i) $listindex(3 $i)
  763.               endif
  764.             endforeach
  765.             $Sender.SendCRLF LIST |END
  766.           case matches NICK |*
  767.             Parse $line
  768.               @l $nick = $substr($1 2 15)
  769.               @l $pass = $3
  770.               // make sure nick is valid and not in use
  771.               if ([$client] === [$nick])
  772.                 // exactly the same nick, don't bother
  773.               else if !($Self.ValidNick($nick))
  774.                 $Sender.SendCRLF ERR |NICK Invalid nickname.
  775.               else if ([$client] != [$nick]) && ($Self.ClientExists($nick))
  776.                 $Sender.SendCRLF ERR |NICK Nickname in use.
  777.               else
  778.                 // update users list
  779.                 @l $newlist = $null
  780.                 foreach ($i; $prop($Self.Users))
  781.                   if ($listindex(0 $i) == $Socket)
  782.                     // replace nick field with chosen nickname
  783.                     @l $newlist = $listcat($newlist $listquote($listreplace(1 1 $nick $i)))
  784.                   else
  785.                     // just append the entry
  786.                     @l $newlist = $listcat($newlist $listquote($i))
  787.                   endif
  788.                   // announce the nick change
  789.                   if ($listindex(2 $i) == 1)
  790.                     $Self.PutClient $listindex(0 $i) NICK |$client $nick
  791.                   endif
  792.                 endforeach
  793.                 @p $Self.Users = $newlist
  794.                 
  795.                 // announce nick change locally
  796.                 $Self.TextOut ecNick *** \b$client\b is now known as \b$nick\b
  797.                 // and update listbox
  798.                 @l $list = $prop($Self.List)
  799.                 @l $idx = $list.Items.IndexOfMask($client *)
  800.                 if ($idx >= 0)
  801.                   Parse $list.Items.GetString($idx)
  802.                     $list.Items.SetString $idx $nick $1-
  803.                   EndParse
  804.                 endif
  805.               endif
  806.             EndParse
  807.           case matches INFO |*
  808.             Parse $line
  809.               if ([$1] != [|MOTD])
  810.                 // relay to other clients
  811.                 $Self.PutAllBut $Socket INFO $1 $client $2-
  812.                 // process locally
  813.                 $Self.HandleInfo INFO $1 $client $2-
  814.               endif
  815.             EndParse
  816.           case matches QUIT |*
  817.             @l $msg = $strtokr(| $line)
  818.             if ([$msg] == [])
  819.               // default quit message is nick
  820.               @l $msg = $client
  821.             endif
  822.             
  823.           case matches :*
  824.             // relay to other clients
  825.             $Self.PutAllBut $Socket $client $line
  826.             // display locally
  827.             $Self.TextOut ecChanText [\b$client\b]\t$strtokr(: $line)
  828.           case matches >*
  829.             // relay to other clients
  830.             $Self.PutAllBut $Socket $client $line
  831.             // display locally
  832.             $Self.TextOut ecAction  * \b$client\b $strtokr(> $line)
  833.           case else
  834.             Parse $line
  835.               $Sender.SendCRLF ERR |$upper($0) Malformed or unknown command
  836.             EndParse
  837.         endswitch
  838.       endif
  839.       
  840.       // find next line
  841.       @l $idx = $strpos($char(10) $buffer)
  842.     endwhile
  843.     
  844.     @p $Self.Buffers = $listreplace($cnum $cnum $listquote($buffer) $prop($Self.Buffers))
  845.   EndMethod
  846.   // command handlers
  847.   Method CmdSay
  848.     $Self.TextOut ecMyChanText [\b$prop($Self.Nick)\b]\t$1-
  849.     $Self.PutAll $prop($Self.Nick) :$1-
  850.   EndMethod
  851.   Method CmdMe
  852.     $Self.TextOut ecAction  * \b$prop($Self.Nick)\b $1-
  853.     $Self.PutAll $prop($Self.Nick) >$1-
  854.   EndMethod
  855.   Method CmdKick
  856.     // kick <nick> [reason]
  857.     if ([$2-] == [])
  858.       @l $reason = $prop($Self.Nick)
  859.     else
  860.       @l $reason = $2-
  861.     endif
  862.     @l $newlist = $null
  863.     foreach ($i; $prop($Self.Users))
  864.       if ([$listindex(1 $i)] == [$1])
  865.         @l $socknum = $listindex(0 $i)
  866.         @l $nick = $listindex(1 $i)
  867.         // notify victim
  868.         $Self.PutClient $socknum QUIT |$nick $reason
  869.         // notify others
  870.         $Self.PutAllBut $socknum KICK |$nick $reason
  871.         // save password
  872.         if ($listindexof($listindex(4 $i) $prop($Self.Passwords)) == -1)
  873.           @p $Self.Passwords = $listcat($prop($Self.Passwords) $listindex(4 $i))
  874.         endif
  875.         // close connection
  876.         @l $socket = $prop($Self.Socket)
  877.         $socket.SetActiveConnection $socknum
  878.         $socket.SClose
  879.         // announce locally
  880.         $Self.TextOut ecKick *** \b$listindex(1 $i)\b was kicked [$reason]
  881.       else
  882.         // add to new list
  883.         @l $newlist = $listcat($newlist $listquote($i))
  884.       endif
  885.     endforeach
  886.     @p $Self.Users = $newlist
  887.   EndMethod
  888.   Method CmdBan
  889.     // ban <nick> [reason]
  890.     if ([$2-] == [])
  891.       @l $reason = $prop($Self.Nick)
  892.     else
  893.       @l $reason = $2-
  894.     endif
  895.     @l $newlist = $null
  896.     foreach ($i; $prop($Self.Users))
  897.       if ([$listindex(1 $i)] == [$1])
  898.         @l $socknum = $listindex(0 $i)
  899.         @l $nick = $listindex(1 $i)
  900.         // notify victim
  901.         $Self.PutClient $socknum BAN |$reason
  902.         // notify others
  903.         $Self.PutAllBut $socknum KICK |$nick $reason (banned)
  904.         // close connection
  905.         @l $socket = $prop($Self.Socket)
  906.         $socket.SetActiveConnection $socknum
  907.         $socket.SClose
  908.         // add to bans
  909.         @p $Self.Bans = $listcat($prop($Self.Bans) $listindex(3 $i))
  910.         // announce locally
  911.         $Self.TextOut ecKick *** \b$listindex(1 $i)\b was banned [$reason]
  912.       else
  913.         // add to new list
  914.         @l $newlist = $listcat($newlist $listquote($i))
  915.       endif
  916.     endforeach
  917.     @p $Self.Users = $newlist
  918.   EndMethod
  919.   Method CmdUnban
  920.     @l $bans = $prop($Self.Bans)
  921.     if ($listindexof($1 $bans) != -1)
  922.       @p $Self.Bans = $listremove($1 $Self.Bans)
  923.       $Self.TextOut ecNotice *** Ban removed: $1
  924.     else
  925.       $Self.TextOut ecError *** $1 is not a banned IP
  926.     endif
  927.   EndMethod
  928.   Method CmdBans
  929.     $Self.TextOut ecNotice *** Banned IPs: $prop($Self.Bans)
  930.   EndMethod
  931.   Method CmdInvite
  932.     if ($currentserver() != 0)
  933.       // generate password
  934.       @l $pmode = $prop($Self.PasswordMode)
  935.       if ($pmode == 0)
  936.         // no password
  937.         @l $pass = $null
  938.       else if ($pmode == 1)
  939.         // master password
  940.         @l $pass = $Self.GenPassword()
  941.       endif
  942.       
  943.       // send invitations
  944.       Halt if [$1-] == []
  945.       foreach ($i; $listfromwords($1-))
  946.         $Self.TextOut clBlue *** Inviting $i...
  947.         // force master passwords if inviting a channel
  948.         if ($ischannel($i)) && ($pmode == 2)
  949.           @l $pmode = 1
  950.           @p $Self.PasswordMode = 1
  951.         endif
  952.         if ($pmode == 2)
  953.           // individual passwords
  954.           @l $pass = $Self.GenPassword()
  955.         endif
  956.         ^CTCP $i SimpleChat $encodeip($prop($Self.Address)) $prop($Self.Port) $pass
  957.       endforeach
  958.     else
  959.       $Self.TextOut ecError *** Not associated with an IRC server
  960.     endif
  961.   EndMethod
  962.   Method CmdPMode
  963.     switch $1
  964.       case 0:
  965.         @p $Self.PasswordMode = 0
  966.         $Self.TextOut ecMode *** Password mode set to 0 (no passwords)
  967.       case 1:
  968.         @p $Self.PasswordMode = 1
  969.         $Self.TextOut ecMode *** Password mode set to 1 (master password)
  970.       case 2:
  971.         @p $Self.PasswordMode = 2
  972.         $Self.TextOut ecMode *** Password mode set to 2 (individual passwords)
  973.       case else
  974.         $Self.TextOut ecError *** Current mode: $prop($Self.PasswordMode). Valid modes: 0 (no passwords), 1 (master password), 2 (individual passwords)
  975.   EndMethod
  976.   Method CmdNick
  977.     // make sure nick is valid and not in use
  978.     @l $curnick = $prop($Self.Nick)
  979.     @l $newnick = $1
  980.     if ([$newnick] == [])
  981.       Halt
  982.     else if ([$newnick] === [$curnick])
  983.       // exactly the same nick, don't bother
  984.     else if !($Self.ValidNick($newnick))
  985.       $Self.TextOut ecError *** Invalid nickname.
  986.     else if ([$curnick] != [$newnick]) && ($Self.ClientExists($newnick))
  987.       $Self.TextOut ecError *** Nickname in use.
  988.     else
  989.       // change local nick
  990.       @p $Self.Nick = $newnick
  991.       // update users list
  992.       @l $newlist = $null
  993.       foreach ($i; $prop($Self.Users))
  994.         if ($listindex(0 $i) == 0)
  995.           // replace nick field with chosen nickname
  996.           @l $newlist = $listcat($newlist $listquote($listreplace(1 1 $newnick $i)))
  997.         else
  998.           // just append the entry
  999.           @l $newlist = $listcat($newlist $listquote($i))
  1000.         endif
  1001.         // announce the nick change
  1002.         if ($listindex(2 $i) == 1)
  1003.           $Self.PutClient $listindex(0 $i) NICK |$curnick $newnick
  1004.         endif
  1005.       endforeach
  1006.       @p $Self.Users = $newlist
  1007.       
  1008.       // announce nick change locally
  1009.       $Self.TextOut ecNick *** \b$curnick\b is now known as \b$newnick\b
  1010.       // and update listbox
  1011.       @l $list = $prop($Self.List)
  1012.       @l $idx = $list.Items.IndexOfMask($curnick *)
  1013.       if ($idx >= 0)
  1014.         Parse $list.Items.GetString($idx)
  1015.           $list.Items.SetString $idx $newnick $1-
  1016.         EndParse
  1017.       endif
  1018.     endif      
  1019.   EndMethod
  1020.   Method CmdQuit
  1021.     if ([$1-] == [])
  1022.       @l $reason = server shutting down
  1023.     else
  1024.       @l $reason = server shutting down: $1-
  1025.     endif
  1026.     // disconnect clients
  1027.     @l $socket = $prop($Self.Socket)
  1028.     foreach ($i; $prop($Self.Users))
  1029.       if ($listindex(0 $i) != 0)
  1030.         if ($listindex(2 $i) == 1)
  1031.           $Self.PutClient $listindex(0 $i) QUIT |$listindex(1 $i) $reason
  1032.         endif
  1033.         $socket.SetActiveConnection $listindex(0 $i)
  1034.         $socket.SClose
  1035.       endif
  1036.     endforeach
  1037.     // die
  1038.     SafeDestroy $Self
  1039.   EndMethod
  1040.   Method CmdQuote
  1041.     $Self.TextOut ecError *** You are the server
  1042.   EndMethod
  1043.   Method CmdList
  1044.     $Self.TextOut ecError *** You are the server
  1045.   EndMethod
  1046.   //
  1047.   Method SendWB
  1048.     $Self.PutAll INFO |WBOARD $prop($Self.Nick) $1-
  1049.   EndMethod
  1050. EndClass
  1051.  
  1052. // Events
  1053.  
  1054. Event SimpleChat "% PRIVMSG % :\ASimpleChat"
  1055.   // CTCP SimpleChat address port password
  1056.   TextOut > . ecCTCP *** SimpleChat invitation from $nick ($user@$host): $decodeip($4):$5 password=$6
  1057.   if ($messagedlg(36 Received SimpleChat invitation from $nick ($user@$host) on $decodeip($4):$5. Do you wish to join?) == 6)
  1058.     @l $schat = $new(TSimpleChatClient ownedby 0)
  1059.     @p $schat.Nick = $N
  1060.     @p $schat.Caption = SimpleChat - connected to $nick ($decodeip($4):$5)
  1061.     @p $schat.TabCaption = $nick
  1062.     $schat.Connect $decodeip($4) $5 $6
  1063.   endif
  1064. EndEvent
  1065.  
  1066. Event <OnMyWhiteboardAction_schat> "*"
  1067.   // $0  = whiteboard name
  1068.   // $1- = command
  1069.   
  1070.   // look for a schat window using this whiteboard
  1071.   foreach ($i; $SChatForms)
  1072.     if ($isa($i TSimpleChatForm)) && ([$prop($i.Whiteboard)] == [$0])
  1073.       // found
  1074.       $i.SendWB $1-
  1075.       Halt
  1076.     endif
  1077.   endforeach
  1078. EndEvent
  1079.  
  1080. // Aliases
  1081.  
  1082. Alias SCHAT
  1083.   // start server and invite: SChat [nick1 nick2...]
  1084.   @l $schat = $new(TSimpleChatServer ownedby 0)
  1085.   @p $schat.Nick = $N
  1086.   @p $schat.Caption = SimpleChat - hosting
  1087.   @p $schat.TabCaption = [Hosting]
  1088.   $schat.Listen
  1089.   
  1090.   // generate password
  1091.   @l $pmode = $prop($schat.PasswordMode)
  1092.   if ($pmode == 0)
  1093.     // no password
  1094.     @l $pass = $null
  1095.   else if ($pmode == 1)
  1096.     // master password
  1097.     @l $pass = $schat.GenPassword()
  1098.   endif
  1099.   
  1100.   // send invitations
  1101.   Halt if [$1-] == []
  1102.   foreach ($i; $listfromwords($1-))
  1103.     $schat.TextOut clBlue *** Inviting $i...
  1104.     // force master passwords if inviting a channel
  1105.     if ($ischannel($i)) && ($pmode == 2)
  1106.       @l $pmode = 1
  1107.       @p $Self.PasswordMode = 1
  1108.     endif
  1109.     if ($pmode == 2)
  1110.       // individual passwords
  1111.       @l $pass = $schat.GenPassword()
  1112.     endif
  1113.     ^CTCP $i SimpleChat $encodeip($prop($schat.Address)) $prop($schat.Port) $pass
  1114.   endforeach
  1115. EndAlias
  1116.  
  1117. Alias SCC
  1118.   // start client: SCC <host> <port> [password]
  1119.   @l $schat = $new(TSimpleChatClient ownedby 0)
  1120.   @p $schat.Nick = $N
  1121.   @p $schat.Caption = SimpleChat - manual connect to $1:$2
  1122.   @p $schat.TabCaption = $1:$2
  1123.   $schat.Connect $1 $2 $3
  1124. EndAlias
  1125.  
  1126. // Menus
  1127.  
  1128. MenuTree MT_SCHAT_CHANNELNICKSPOPUP
  1129.   M_SCHAT     <none> 0 0 &SimpleChat
  1130. EndMenuTree
  1131.  
  1132. MenuHint M_SCHAT on MT_SCHAT_CHANNELNICKSPOPUP = Invite this person to a fast private channel
  1133. MenuItem M_SCHAT on MT_SCHAT_CHANNELNICKSPOPUP
  1134.   SChat $1-
  1135. EndMenuItem
  1136.  
  1137. #// default items
  1138. #
  1139. #MenuHint M_WHOIS on MT_CHANNELNICKSPOPUP = Retrieve information about the user
  1140. #MenuHint M_WII on MT_CHANNELNICKSPOPUP = Retrieve information and idle time
  1141. #MenuHint M_QUERY on MT_CHANNELNICKSPOPUP = Create a private message window for the user
  1142. #MenuHint M_DCCCHAT on MT_CHANNELNICKSPOPUP = Secure, fast private message window
  1143. #MenuHint M_DCCWBOARD on MT_CHANNELNICKSPOPUP = Shared drawing board
  1144. #MenuHint M_DCCSEND on MT_CHANNELNICKSPOPUP = Send a file using the slow DCC protocol
  1145. #MenuHint M_TDCCSEND on MT_CHANNELNICKSPOPUP = Send a file using Turbo DCC
  1146. #MenuHint M_CTCPTIME on MT_CHANNELNICKSPOPUP = Read the user's clock
  1147. #MenuHint M_CTCPVER on MT_CHANNELNICKSPOPUP = Check the user's client version
  1148. #MenuHint M_CTCPPING on MT_CHANNELNICKSPOPUP = Calculate round trip time to the user
  1149. #MenuHint M_OP on MT_CHANNELNICKSPOPUP = Op the user
  1150. #MenuHint M_DEOP on MT_CHANNELNICKSPOPUP = Deop the user
  1151. #MenuHint M_VOICE on MT_CHANNELNICKSPOPUP = Voice the user
  1152. #MenuHint M_DEVOICE on MT_CHANNELNICKSPOPUP = Devoice the user
  1153. #MenuHint M_KICK on MT_CHANNELNICKSPOPUP = Kick the user out of the channel
  1154. #MenuHint M_KICKBAN on MT_CHANNELNICKSPOPUP = Kick and ban the user from the channel
  1155. #
  1156. #MenuItem <DoubleClick> on MT_CHANNELNICKSPOPUP
  1157. #  Whois $1
  1158. #EndMenuItem
  1159. #
  1160. #MenuItem M_WHOIS on MT_CHANNELNICKSPOPUP
  1161. #  foreach ($i; $listfromwords($1-))
  1162. #    Whois $i
  1163. #  endforeach
  1164. #EndMenuItem
  1165. #
  1166. #MenuItem M_WII on MT_CHANNELNICKSPOPUP
  1167. #  foreach ($i; $listfromwords($1-))
  1168. #    Wii $i
  1169. #  endforeach
  1170. #EndMenuItem
  1171. #
  1172. #MenuItem M_QUERY on MT_CHANNELNICKSPOPUP
  1173. #  foreach ($i; $listfromwords($1-))
  1174. #    Query $i
  1175. #  endforeach
  1176. #EndMenuItem
  1177. #
  1178. #MenuItem M_DCCCHAT on MT_CHANNELNICKSPOPUP
  1179. #  foreach ($i; $listfromwords($1-))
  1180. #    DCC Chat $i
  1181. #  endforeach
  1182. #EndMenuItem
  1183. #
  1184. #MenuItem M_DCCWBOARD on MT_CHANNELNICKSPOPUP
  1185. #  foreach ($i; $listfromwords($1-))
  1186. #    DCC Whiteboard $i
  1187. #  endforeach
  1188. #EndMenuItem
  1189. #
  1190. #MenuItem M_DCCSEND on MT_CHANNELNICKSPOPUP
  1191. #  foreach ($i; $listfromwords($1-))
  1192. #    DCC Send $i
  1193. #  endforeach
  1194. #EndMenuItem
  1195. #
  1196. #MenuItem M_TDCCSEND on MT_CHANNELNICKSPOPUP
  1197. #  foreach ($i; $listfromwords($1-))
  1198. #    TDCC Send $i
  1199. #  endforeach
  1200. #EndMenuItem
  1201. #
  1202. #// I would love to use a multi-variable foreach here, but some
  1203. #// efnet servers don't allow /msg nick1,nick2,nick3 anymore.
  1204. #MenuItem M_CTCPTIME on MT_CHANNELNICKSPOPUP
  1205. #  foreach ($i; $listfromwords($1-))
  1206. #    CTCP $i TIME
  1207. #  endforeach
  1208. #EndMenuItem
  1209. #
  1210. #MenuItem M_CTCPVER on MT_CHANNELNICKSPOPUP
  1211. #  foreach ($i; $listfromwords($1-))
  1212. #    CTCP $i VERSION
  1213. #  endforeach
  1214. #EndMenuItem
  1215. #
  1216. #MenuItem M_CTCPPING on MT_CHANNELNICKSPOPUP
  1217. #  foreach ($i; $listfromwords($1-))
  1218. #    Ping $1
  1219. #  endforeach
  1220. #EndMenuItem
  1221. #
  1222. #MenuItem M_OP on MT_CHANNELNICKSPOPUP
  1223. #  foreach ($a,$b,$c,$d; $listfromwords($1-))
  1224. #    Mode $C +oooo $a $b $c $d
  1225. #  endforeach
  1226. #EndMenuItem
  1227. #
  1228. #MenuItem M_DEOP on MT_CHANNELNICKSPOPUP
  1229. #  foreach ($a,$b,$c,$d; $listfromwords($1-))
  1230. #    Mode $C -oooo $a $b $c $d
  1231. #  endforeach
  1232. #EndMenuItem
  1233. #
  1234. #MenuItem M_VOICE on MT_CHANNELNICKSPOPUP
  1235. #  foreach ($a,$b,$c,$d; $listfromwords($1-))
  1236. #    Mode $C +vvvv $a $b $c $d
  1237. #  endforeach
  1238. #EndMenuItem
  1239. #
  1240. #MenuItem M_DEVOICE on MT_CHANNELNICKSPOPUP
  1241. #  foreach ($a,$b,$c,$d; $listfromwords($1-))
  1242. #    Mode $C -vvvv $a $b $c $d
  1243. #  endforeach
  1244. #EndMenuItem
  1245. #
  1246. #MenuItem M_KICK on MT_CHANNELNICKSPOPUP
  1247. #  foreach ($i; $listfromwords($1-))
  1248. #    Kick $C $i
  1249. #  endforeach
  1250. #EndMenuItem
  1251. #
  1252. #MenuItem M_KICKBAN on MT_CHANNELNICKSPOPUP
  1253. #  foreach ($i; $listfromwords($1-))
  1254. #    KB $C $i
  1255. #  endforeach
  1256. #EndMenuItem
  1257.  
  1258. // Initialization
  1259.  
  1260. MergeMenu MT_SCHAT_CHANNELNICKSPOPUP after MT_CHANNELNICKSPOPUP
  1261. @ $SChatForms = $null
  1262.